package T01_数据库事务介绍;

import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 *1.什么叫数据库事务
 *  >事务 一组逻辑操作单元,使数据库从一种状态变换到另一种状态
 *       >一组逻辑操作单元,一个或多个DML操作
 *2.事务处理的原则
 *  >保证所有事务都作为一个工作单元来执行，即使出现了故障，
 *   都不能改变这种执行方式。当在一个事务中执行多个操作时，
 *   要么所有的事务都被提交(commit)，那么这些修改就永久地
 *   保存下来；要么数据库管理系统将放弃所作的所有修改，
 *   整个事务回滚(rollback)到最初状态。
 *
 *3.数据一旦提交就不可回滚
 *
 *4.那些操作会导致数据的自动提交
 *  >DDL操作一旦执行都会自动提交
 *      >set autocommit=false的方式 对DDL操作失效
 *  >DML默认情况下,一旦执行,就会自动提交
 *      >我们可以通过set autocommit=false的方式取消DML操作的自动提交
 *  >默认在关闭连接时,会自动的提交数据
 *  注意:是这三种情况都得被同时避免
 *5.8.0文档说关闭连接是是否提交数据依赖于具体实现
 */
public class TransactionTest {

    //************************未考虑数据库事务情况下的一个转账操作*****************************
    /**
     * 针对于数据表user_tablel来说
     * AA用户给BB用户转账100
     * update user_table set balance =balance-100 where user="AA";
     * update user_table set balance =balance+100 where user="BB";
     */
    @Test
    public   void  testUpdate(){
        String sql1="update user_table set balance =balance-100 where user=?";
        update01(sql1,"AA");

        //模拟网络异常
        //System.out.println(10/0);//AA用户白白损失100
        String sql2="update user_table set balance =balance+100 where user=?";
        update01(sql2,"BB");

        System.out.println("转账成功");
    }
    //通用的增删改操作----未考虑事务version 1.0
    public static   boolean  update01(String sql,Object ...args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            //1.获取数据库连接
            conn=JDBCUtils.getConnection();
            //2.预编译sql语句,返回PreparedStatement的实例
            ps=conn.prepareStatement(sql);
            //3.填充占位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);//小心参数声明错误
            }
            //System.out.println();
            return  ps.executeUpdate()>0?true:false;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //资源的关闭
            JDBCUtils.closeResource(conn,ps);
        }
        return  false;
    }







    //************************考虑数据库事务情况下的一个转账操作*****************************
    @Test
    public   void  testUpdateWithTx()  {
        Connection connection=null;
        try {
            //把连接给串起来了 解决了不是同一个连接 有关闭情况的问题
            connection=JDBCUtils.getConnection();
            System.out.println(connection.getAutoCommit());//默认是true
            //1.取消数据的自动提交
            connection.setAutoCommit(false);
            String sql1="update user_table set balance =balance-100 where user=?";
            update02(connection,sql1,"AA");

            //模拟网络异常
            System.out.println(10/0);//AA用户白白损失100

            String sql2="update user_table set balance =balance+100 where user=?";
            update02(connection,sql2,"BB");
            System.out.println("转账成功");

            //2.提交数据
            connection.commit();

        } catch (Exception e) {
            e.printStackTrace();
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            //修改其为自动提交数据
            //主要针对于使用数据库连接池的使用
            try {
                connection.setAutoCommit(true);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            JDBCUtils.closeResource(connection,null);
        }
    }




    //通用的增删改操作----考虑上事务version 2.0
    public static   boolean  update02(Connection conn,String sql,Object ...args) {
        PreparedStatement ps=null;
        try {
            //1.预编译sql语句,返回PreparedStatement的实例
            ps=conn.prepareStatement(sql);
            //2.填充占位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);//小心参数声明错误
            }
            //3.执行
            return  ps.executeUpdate()>0?true:false;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //4.资源的关闭
            JDBCUtils.closeResource(null,ps);
        }
        return  false;
    }
}
